package com.qdlc.p2p.biz.freemarker.generate;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.qdlc.p2p.common.constant.Global;
import com.qdlc.p2p.common.util.DateUtil;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.DefaultResourceLoader;

import com.google.common.collect.Maps;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * 代码生成器
 * @author lhm
 * @version 2014-03-25
 */
public class Generate {
	
	private static Logger logger = LoggerFactory.getLogger(Generate.class);
	
	private static boolean hasDate = false;

	public static void main(String[] args) throws Exception {

		// ========== ↓↓↓↓↓↓ 执行前请修改参数，谨慎执行。↓↓↓↓↓↓ ====================

		// 主要提供基本功能模块代码生成。
		// 目录生成结构：{packageName}/{moduleName}/{dao,entity,service,web}/{subModuleName}/{className}
		
		// packageName 包名
		String packageName = "com.rd.p2p.additional";
		
		String moduleName = "finanFlow";			// 模块名，例：sys

		String subModuleName = "";				// 子模块名（可选） 
		String classAuthor = "wjx";		// 类作者，例：lhm
		String functionName = "项目待还计划";			// 功能名，例：用户
		String table_name = Global.DB_PREFIX + "additional_flow_repay_plan";


		Boolean needsDomain = true;  // 是否生成实体类
		Boolean needsAction = false;  // 是否生成Action
		Boolean needsService = false;  // 是否生成Service和ServiceImpl
		Boolean needsDao = true;  // 是否生成Dao和DaoImpl
		Boolean needsManager = false;  // 是否生成Manager页面
		Boolean needsAddPage = false;  // 是否生成添加页面
		Boolean needsEditPage = false;  // 是否生成编辑页面


		// 是否启用生成工具
		Boolean isEnable = true;			
		
		// ========== ↑↑↑↑↑↑ 执行前请修改参数，谨慎执行。↑↑↑↑↑↑ ====================
		
		if (!isEnable){
			logger.error("请启用代码生成工具，设置参数：isEnable = true");
			return;
		}
		
		if (StringUtils.isBlank(moduleName) || StringUtils.isBlank(moduleName) 
				|| StringUtils.isBlank(table_name) || StringUtils.isBlank(functionName)){
			logger.error("参数设置错误：包名、模块名、类名、功能名不能为空。");
			return;
		}
		
		String className = toUpper(table_name.substring(2));			// 类名
		
		// 获取文件分隔符
		String separator = File.separator;
		
		// 获取工程路径
		File projectPath = new DefaultResourceLoader().getResource("").getFile();
		while(!new File(projectPath.getPath()+separator+"src"+separator+"main").exists()){
			projectPath = projectPath.getParentFile();
		}
		logger.info("Project Path: {}", projectPath);
		
		// 模板文件路径
		String tplPath = StringUtils.replace(projectPath+"/src/main/java/com/rd/p2p/additional/generate/template", "/", separator);
		logger.info("Template Path: {}", tplPath);
		
		// Java文件路径
		String javaPath = StringUtils.replaceEach(projectPath+"/src/main/java/"+StringUtils.lowerCase(packageName), 
				new String[]{"/", "."}, new String[]{separator, separator});
		logger.info("Java Path: {}", javaPath);
		
		// 视图文件路径
		String viewPath = StringUtils.replace(projectPath+"/src/main/webapp/WEB-INF/views", "/", separator);
		logger.info("View Path: {}", viewPath);
		
		// 代码模板配置
		Configuration cfg = new Configuration();
		cfg.setDirectoryForTemplateLoading(new File(tplPath));

		// 定义模板变量
		Map<String, Object> model = Maps.newHashMap();
		model.put("packageName", StringUtils.lowerCase(packageName));
		model.put("moduleName", moduleName);
		model.put("subModuleName", StringUtils.isNotBlank(subModuleName)?"/"+StringUtils.lowerCase(subModuleName):"");
		model.put("className", StringUtils.uncapitalize(className));
		model.put("ClassName", StringUtils.capitalize(className));
		model.put("classAuthor", StringUtils.isNotBlank(classAuthor)?classAuthor:"Generate Tools");
		model.put("classDate", getDate());
		model.put("functionName", functionName);
		model.put("tableName", table_name);
		model.put("urlPrefix", model.get("moduleName")+(StringUtils.isNotBlank(subModuleName)
				?"/"+StringUtils.lowerCase(subModuleName):"")+"/"+model.get("className"));
		model.put("viewPrefix", //StringUtils.substringAfterLast(model.get("packageName"),".")+"/"+
				model.get("urlPrefix"));
		model.put("permissionPrefix", model.get("moduleName")+(StringUtils.isNotBlank(subModuleName)
				?":"+StringUtils.lowerCase(subModuleName):"")+":"+model.get("className"));
		
		// 表数据取得
		model.put("list", getList(table_name));
		model.put("hasDate", hasDate);
		
		Template template = null;
		String content = "";
		String filePath = "";

		// 生成 domain
		if (needsDomain) {
			template = cfg.getTemplate("domain.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"domain"
					+separator+model.get("ClassName")+".java";
			writeFile(content, filePath);
			logger.info("Domain: {}", filePath);
		}

		
		// 生成 Dao
		if (needsDao) {
			template = cfg.getTemplate("dao.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"dao"+separator
					+model.get("ClassName")+"Dao.java";
			writeFile(content, filePath);
			logger.info("Dao: {}", filePath);
			// 生成DaoImpl
			template = cfg.getTemplate("daoImpl.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"dao"+separator+"jdbc"+separator
					+model.get("ClassName")+"DaoImpl.java";
			writeFile(content, filePath);
			logger.info("daoImpl: {}", filePath);
		}

		
		// 生成 Service
		if (needsService) {
			template = cfg.getTemplate("service.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"service"+separator
					+model.get("ClassName")+"Service.java";
			writeFile(content, filePath);
			logger.info("Service: {}", filePath);
			// 生成 ServiceImpl
			template = cfg.getTemplate("serviceImpl.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"service"+separator+"impl"+separator
					+model.get("ClassName")+"ServiceImpl.java";
			writeFile(content, filePath);
			logger.info("serviceImpl: {}", filePath);
		}
		
		// 生成 Action
		if (needsAction) {
			template = cfg.getTemplate("action.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"web"+separator+"action"+separator
					+model.get("ClassName")+"Action.java";
			writeFile(content, filePath);
			logger.info("Action: {}", filePath);
		}

		// 生成 manager
		if (needsManager) {
			template = cfg.getTemplate("manager.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = viewPath+separator+StringUtils.substringAfterLast(model.get("packageName").toString(),".")
					+separator+model.get("moduleName")+separator+StringUtils.lowerCase(subModuleName)
					+separator+model.get("className")+"Manager.ftl";
			writeFile(content, filePath);
			logger.info("manager: {}", filePath);		
		}

		// 生成 addPage
		if (needsAddPage) {
			template = cfg.getTemplate("addPage.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = viewPath+separator+StringUtils.substringAfterLast(model.get("packageName").toString(),".")
					+separator+model.get("moduleName")+separator+StringUtils.lowerCase(subModuleName)
					+separator+model.get("className")+"AddPage.ftl";
			writeFile(content, filePath);
			logger.info("addPage: {}", filePath);
		}

		// 生成 editPage
		if (needsEditPage) {
			template = cfg.getTemplate("editPage.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = viewPath+separator+StringUtils.substringAfterLast(model.get("packageName").toString(),".")
					+separator+model.get("moduleName")+separator+StringUtils.lowerCase(subModuleName)
					+separator+model.get("className")+"EditPage.ftl";
			writeFile(content, filePath);
			logger.info("editPage: {}", filePath);
		}

		logger.info("Generate Success.");
	}
	
	public static List<Table> getList(String table_name){
		// 数据库连接
		String table_schema = "p2pv2";
		String user = "root";
		String password = "qudou.com";
		String url = "jdbc:mysql://192.168.0.70/p2pv2?useUnicode=true&characterEncoding=utf8";
		
		Connection conn = null;
		Statement stmt = null;
		
		List<Table> list = new ArrayList<Table>();
		
		try {
			Class.forName("com.mysql.jdbc.Driver"); // 加载mysq驱动
		} catch (ClassNotFoundException e) {
			e.printStackTrace();// 打印出错详细信息
		}
		
		try {
			conn = DriverManager.getConnection(url, user, password);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		try {
			stmt = conn.createStatement();
			String sql = "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT FROM INFORMATION_SCHEMA. `COLUMNS` WHERE table_name = '"
				+ table_name + "'  AND table_schema = '" + table_schema + "'";
			ResultSet rs = stmt.executeQuery(sql);
			while (rs.next()) {
				Table table = new Table();
				table.setColumnName(toUpper(rs.getString("COLUMN_NAME")));
				table.setColumnNameUpper( StringUtils.capitalize(table.getColumnName()));
				table.setDataType(sqlType2JavaType(rs.getString("DATA_TYPE")));
				if (table.getDataType().equals("Date")) {
					hasDate = true;
				}
				table.setColumnComment(rs.getString("COLUMN_COMMENT"));
				list.add(table);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				stmt.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}

		}
		
		return list;
	}
	
	/**
	 * “_”+小写 转成大写字母
	 * 
	 * @param str
	 * @return
	 */
	private static String toUpper(String str) {
		char[] charArr = str.toCharArray();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < charArr.length; i++) {
			if (charArr[i] == '_') {
				sb.append(String.valueOf(charArr[i + 1]).toUpperCase());
				i = i + 1;
			} else {
				sb.append(charArr[i]);
			}
		}
		return sb.toString();
	}
	
	/**
	 * 功能：获得列的数据类型
	 * 
	 * @param sqlType
	 * @return
	 */
	private static String sqlType2JavaType(String sqlType) {

		if (sqlType.equalsIgnoreCase("bit")) {
			return "boolean";
		} else if (sqlType.equalsIgnoreCase("tinyint")) {
			return "byte";
		} else if (sqlType.equalsIgnoreCase("smallint")) {
			return "short";
		} else if (sqlType.equalsIgnoreCase("int")) {
			return "int";
		} else if (sqlType.equalsIgnoreCase("bigint")) {
			return "long";
		} else if (sqlType.equalsIgnoreCase("float")) {
			return "float";
		} else if (sqlType.equalsIgnoreCase("decimal") || sqlType.equalsIgnoreCase("numeric")
				|| sqlType.equalsIgnoreCase("real") || sqlType.equalsIgnoreCase("money")
				|| sqlType.equalsIgnoreCase("smallmoney") || sqlType.equalsIgnoreCase("double")) {
			return "double";
		} else if (sqlType.equalsIgnoreCase("varchar") || sqlType.equalsIgnoreCase("char")
				|| sqlType.equalsIgnoreCase("nvarchar") || sqlType.equalsIgnoreCase("nchar")
				|| sqlType.equalsIgnoreCase("text")) {
			return "String";
		} else if (sqlType.equalsIgnoreCase("datetime") || sqlType.equalsIgnoreCase("date")) {
			return "Date";
		} else if (sqlType.equalsIgnoreCase("image")) {
			return "Blod";
		}

		return "String";
	}
	
	/**
	 * 将内容写入文件
	 * @param content
	 * @param filePath
	 */
	public static void writeFile(String content, String filePath) {
		try {
			if (createFile(filePath)){
				FileWriter fileWriter = new FileWriter(filePath, true);
				BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
				bufferedWriter.write(content);
				bufferedWriter.close();
				fileWriter.close();
			}else{
				logger.info("生成失败，文件已存在！");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 创建单个文件
	 * @param descFileName 文件名，包含路径
	 * @return 如果创建成功，则返回true，否则返回false
	 */
	public static boolean createFile(String descFileName) {
		File file = new File(descFileName);
		if (file.exists()) {
			logger.debug("文件 " + descFileName + " 已存在!");
			return false;
		}
		if (descFileName.endsWith(File.separator)) {
			logger.debug(descFileName + " 为目录，不能创建目录!");
			return false;
		}
		if (!file.getParentFile().exists()) {
			// 如果文件所在的目录不存在，则创建目录
			if (!file.getParentFile().mkdirs()) {
				logger.debug("创建文件所在的目录失败!");
				return false;
			}
		}

		// 创建文件
		try {
			if (file.createNewFile()) {
				logger.debug(descFileName + " 文件创建成功!");
				return true;
			} else {
				logger.debug(descFileName + " 文件创建失败!");
				return false;
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.debug(descFileName + " 文件创建失败!");
			return false;
		}
	}
	
	public static String getDate() {
		SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
		String str = format.format(DateUtil.getNow());
		return str;
	}
}
